<!-- 我的视图 -->

<template>
  <div
    ref="view"
    v-bind="viewProps"
    @mousedown="mouseDown"
    @mouseup="mouseUp"
    @mousemove="mouseMove"
    @mousewheel="mouseWheel"
    @contextmenu.prevent="CORE.doNothing"
  >
    <ViewBackground @loaded="toLoaded">
      <ViewPoint v-for="item in mapPoint" :key="item.id" :obj="item" />
      <ViewLine v-for="item in mapLine" :key="item.id" :obj="item" />
    </ViewBackground>

    <ViewName />

    <ViewStatus />

    <ViewRuler />

    <ViewCheckbox v-if="map_param.deviceCategoryId === '24'" />
  </div>
</template>

<script>
// ============================== 导入依赖 ============================== //

import CORE from '@/CORE'

const RORATE = {
  clientX: 0, // 开始时的 X 值
  clientY: 0, // 开始时的 Y 值
}

const MORE_LIST = [1.2, 1.4, 1.6, 1.8, 2, 2.4, 2.8, 3.2, 3.6, 4, 5]

// ============================== 导出组件 ============================== //

export default {
  /**
   * 名称定义 (实际使用名称)
   */
  name: 'MapView',

  /**
   * 混入列表 (配置选项合并)
   */
  mixins: [CORE.mixWeb('map', 'map_'), CORE.mixInfo('map', 'map_'), CORE.mixSelect('map', 'map_')],

  /**
   * 组件导入 (Abc.vue + Abc/index.vue)
   */
  ...CORE.components(require.context('./', true, /vue$/)),

  /**
   * 状态数据 (函数返回对象)
   */
  data() {
    return {
      initScale: 1, // 初始缩放
      SCALE: [1], // 缩放倍数列表 (基于初始缩放)
      scaleIndex: 0, // 当前缩放序号

      transX: 0, // 横向偏移
      transY: 0, // 纵向偏移

      inTrans: false, // 是否正在位移中
      inRotate: false, // 是否正在旋转中

      viewX: 960, // 视图中心 X 值
      viewY: 540, // 视图中心 Y 值
      viewW: 1920, // 视图宽度
      viewH: 1080, // 视图高度
      mapW: 1920, // 地图宽度
      mapH: 1080, // 地图高度
      moveX: 0, // 拖动的起始 X 值
      moveY: 0, // 拖动的起始 Y 值
    }
  },

  /**
   * 计算属性 (慎用箭头函数)
   */
  computed: {
    /**
     * 缩放倍数
     */
    scale() {
      const { initScale, SCALE, scaleIndex } = this
      const more = scaleIndex - SCALE.length // 超出个数

      // 原图被缩小
      if (initScale < 1) {
        if (more < 0) return CORE.mul(initScale, SCALE[scaleIndex]) // 未达原图大小
        else return MORE_LIST[more] // 超过原图大小
      }

      // 原图被放大
      const moreList = [1, ...MORE_LIST]
      return initScale * moreList[more]
    },

    /**
     * 所有倍数 (达到原始尺寸之后可以继续放大 10 次)
     */
    ALL_SCALE() {
      const { initScale, SCALE } = this
      if (initScale > 1) return [1, ...MORE_LIST]
      const moreList = MORE_LIST.map((more) => +(more / initScale).toFixed(1))
      return [...SCALE, ...moreList]
    },

    /**
     * 缩放后的宽度
     */
    scaleW() {
      return CORE.mul(this.mapW, this.scale)
    },

    /**
     * 缩放后的高度
     */
    scaleH() {
      return CORE.mul(this.mapH, this.scale)
    },

    /**
     * 放大时偏移量的倍数
     */
    multipleLarge() {
      const { initScale, ALL_SCALE, scaleIndex, scale } = this
      const next = CORE.mul(initScale, ALL_SCALE[scaleIndex + 1])
      return CORE.div(next - scale, scale)
    },

    /**
     * 缩小时偏移量的倍数
     */
    multipleSmall() {
      const { initScale, ALL_SCALE, scaleIndex, scale } = this
      const prev = CORE.mul(initScale, ALL_SCALE[scaleIndex - 1])
      return CORE.div(prev - scale, scale)
    },

    /**
     * 最大时偏移量的倍数
     */
    multipleMax() {
      const { initScale, ALL_SCALE, SCALE, scale } = this
      const last = CORE.mul(initScale, ALL_SCALE[SCALE.length + 10])
      return CORE.div(last - scale, scale)
    },

    /**
     * 最大横向偏移
     */
    maxTransX() {
      const x = CORE.div(this.scaleW - this.viewW, 2)
      return x < 0 ? 0 : x
    },

    /**
     * 最大纵向偏移
     */
    maxTransY() {
      const y = CORE.div(this.scaleH - this.viewH, 2)
      return y < 0 ? 0 : y
    },

    /**
     * 视图属性
     */
    viewProps() {
      const { inTrans, inRotate } = this
      const name = 'Secure-MapView'
      const trans = inTrans ? ` ${name}-inTrans` : ''
      const rotate = inRotate ? ` ${name}-inRotate` : ''
      return { class: `flexCC ${name}${trans}${rotate}` }
    },

    /**
     * 地图的点位列表
     */
    mapPoint() {
      const { map_param: { deviceCategoryId, checkboxList }, map_list } = this
      if (deviceCategoryId !== '24') return map_list
      return map_list.filter((item) => checkboxList.some((code) => item.pointTypeCode === code))
    },

    /**
     * 地图的周界列表
     */
    mapLine() {
      return this.map_select.filter((item) => !CORE.isEmpty(item.site))
    },
  },

  /**
   * 监听属性 (深度 deep 首次 immediate)
   */
  watch: {
    /**
     * 监听信息就绪
     */
    map_readyInfo(ready) {
      if (ready) this.initTransScale()
    },
  },

  /**
   * 本地方法 (轻量重要在前)
   */
  methods: {
    /**
     * 图片加载完成
     */
    toLoaded(data) {
      Object.assign(this, data)
    },

    /**
     * 检查是否可移动
     */
    checkNoMove(el) {
      if (!el) return false
      if (CORE.isString(el.className) && el.className.includes('noMove')) return true
      return this.checkNoMove(el.parentElement)
    },

    /**
     * 鼠标按下
     */
    mouseDown({ srcElement, button, clientX, clientY }) {
      if (this.checkNoMove(srcElement)) return

      button === 0 && this.transStart(clientX, clientY)
      // button === 2 && this.rotateStart(clientX, clientY)
    },

    /**
     * 鼠标弹起
     */
    mouseUp({ button }) {
      button === 0 && this.transStop()
      button === 1 && this.initTransScale()
      button === 2 && this.rotateStop()
    },

    /**
     * 鼠标移动
     */
    mouseMove({ clientX, clientY }) {
      this.inTrans && this.transDoing(clientX, clientY)
      this.inRotate && this.rotateDoing(clientX, clientY)
    },

    /**
     * 位移开始
     */
    transStart(clientX, clientY) {
      this.inTrans = true
      this.moveX = clientX - this.transX
      this.moveY = clientY - this.transY
    },

    /**
     * 位移中
     */
    transDoing(clientX, clientY) {
      const transX = clientX - this.moveX
      const transY = clientY - this.moveY
      this.transX = this.fixTrans(transX, 'X')
      this.transY = this.fixTrans(transY, 'Y')
    },

    /**
     * 位移结束
     */
    transStop() {
      this.inTrans = false
    },

    /**
     * 旋转开始
     */
    rotateStart(clientX, clientY) {
      this.inRotate = true
      Object.assign(RORATE, { clientX, clientY })
    },

    /**
     * 旋转中
     */
    rotateDoing(clientX, clientY) {
      const [X, Y] = this.getCenter()
      const [x1, y1, x2, y2] = [RORATE.clientX - X, RORATE.clientY - Y, clientX - X, clientY - Y]
      x1 * y2 > x2 * y1 ? this.rotate++ : this.rotate--
      Object.assign(RORATE, { clientX, clientY })
    },

    /**
     * 旋转结束
     */
    rotateStop() {
      this.inRotate = false
    },

    /**
     * 回到初始的位移和缩放
     */
    initTransScale() {
      this.scaleIndex = this.transX = this.transY = 0
    },

    /**
     * 滚轮缩放
     */
    async mouseWheel(e) {
      await this.$nextTick()

      const { wheelDelta, clientX, clientY } = e
      const { viewX, viewY, scaleIndex, SCALE, multipleLarge, multipleSmall, multipleMax } = this
      let { transX, transY } = this

      // 放大
      if (wheelDelta > 0 && scaleIndex < SCALE.length + 10) { // 达到原始尺寸之后可以继续放大 10 次
        this.scaleIndex++ // 序号变大，并触发 maxTransX 和 maxTransY 更新
        transX -= ((clientX - viewX - transX) * multipleLarge) | 0
        transY -= ((clientY - viewY - transY) * multipleLarge) | 0
      }

      // 缩小
      if (wheelDelta < 0 && scaleIndex) {
        this.scaleIndex-- // 序号变小，并触发 maxTransX 和 maxTransY 更新
        transX -= ((clientX - viewX - transX) * multipleSmall) | 0
        transY -= ((clientY - viewY - transY) * multipleSmall) | 0
      }

      // 最大
      if (wheelDelta === 0) {
        this.scaleIndex = SCALE.length + 10 // 序号变大，并触发 maxTransX 和 maxTransY 更新
        transX -= ((clientX - viewX - transX) * multipleMax) | 0
        transY -= ((clientY - viewY - transY) * multipleMax) | 0
      }

      // 修复
      this.transX = this.fixTrans(transX, 'X')
      this.transY = this.fixTrans(transY, 'Y')

      this.mouseMove(e)
    },

    /**
     * 位移修复 (设置偏移不出界)
     */
    fixTrans(trans, type) {
      const max = this[`maxTrans${type}`]
      return trans > max ? max : trans < -max ? -max : trans
    },
  },
}
</script>

<style lang="scss">
@import './index.scss';
</style>
